行為是 yii\base\Behavior 或子類別的實例。 行為,也稱為 mixins,讓您可以在不需更改類別繼承結構的情況下,增強現有 component 類別的功能。 將行為附加到元件會將行為的方法和屬性「注入」到元件中,使這些方法和屬性可以像在元件類別本身中定義一樣被存取。 此外,行為可以回應元件觸發的 事件,這使得行為也可以自訂元件的正常程式碼執行。
要定義行為,請建立一個類別,該類別繼承 yii\base\Behavior 或繼承子類別。 例如
namespace app\components;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public $prop1;
private $_prop2;
public function getProp2()
{
return $this->_prop2;
}
public function setProp2($value)
{
$this->_prop2 = $value;
}
public function foo()
{
// ...
}
}
上面的程式碼定義了行為類別 app\components\MyBehavior
,它具有兩個屬性 prop1
和 prop2
以及一個方法 foo()
。 請注意,屬性 prop2
是透過 getter getProp2()
和 setter setProp2()
定義的。 這是因為 yii\base\Behavior 繼承了 yii\base\BaseObject,因此支援透過 getter 和 setter 定義 屬性。
因為這個類別是一個行為,當它被附加到一個元件時,該元件也將具有 prop1
和 prop2
屬性以及 foo()
方法。
提示: 在行為中,您可以透過 yii\base\Behavior::$owner 屬性存取附加行為的元件。
注意: 如果行為的 yii\base\Behavior::__get() 和/或 yii\base\Behavior::__set() 方法被覆寫,您也需要覆寫 yii\base\Behavior::canGetProperty() 和/或 yii\base\Behavior::canSetProperty()。
如果行為需要回應其附加到的元件所觸發的事件,則應覆寫 yii\base\Behavior::events() 方法。 例如
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
events() 方法應傳回事件及其對應處理常式的清單。 上面的範例宣告了 EVENT_BEFORE_VALIDATE 事件存在,並定義了其處理常式 beforeValidate()
。 在指定事件處理常式時,您可以使用以下格式之一
[$object, 'methodName']
;事件處理常式的簽章應如下所示,其中 $event
指的是事件參數。 有關事件的更多詳細資訊,請參閱 事件 章節。
function ($event) {
}
您可以靜態或動態地將行為附加到 元件。 後者在實務中更常見。
要靜態地附加行為,請覆寫要附加行為的元件類別的 behaviors() 方法。 behaviors() 方法應傳回行為 配置 的清單。 每個行為配置可以是行為類別名稱或配置陣列
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// anonymous behavior, behavior class name only
MyBehavior::class,
// named behavior, behavior class name only
'myBehavior2' => MyBehavior::class,
// anonymous behavior, configuration array
[
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
],
// named behavior, configuration array
'myBehavior4' => [
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
您可以透過指定對應於行為配置的陣列鍵來將名稱與行為關聯。 在這種情況下,該行為稱為具名行為。 在上面的範例中,有兩個具名行為:myBehavior2
和 myBehavior4
。 如果行為未與名稱關聯,則稱為匿名行為。
要動態地附加行為,請呼叫要附加行為的元件的 yii\base\Component::attachBehavior() 方法
use app\components\MyBehavior;
// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior());
// attach a behavior class
$component->attachBehavior('myBehavior2', MyBehavior::class);
// attach a configuration array
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
]);
您可以使用 yii\base\Component::attachBehaviors() 方法一次附加多個行為
$component->attachBehaviors([
'myBehavior1' => new MyBehavior(), // a named behavior
MyBehavior::class, // an anonymous behavior
]);
您也可以透過 配置 附加行為,如下所示
[
'as myBehavior2' => MyBehavior::class,
'as myBehavior3' => [
'class' => MyBehavior::class,
'prop1' => 'value1',
'prop2' => 'value2',
],
]
有關更多詳細資訊,請參閱 配置 章節。
要使用行為,首先依照上述說明將其附加到 元件。 一旦行為附加到元件,其使用方式就很簡單。
您可以透過附加行為的元件存取行為的公有成員變數或 getter 和/或 setter 定義的 屬性
// "prop1" is a property defined in the behavior class
echo $component->prop1;
$component->prop1 = $value;
您也可以類似地呼叫行為的公有方法
// foo() is a public method defined in the behavior class
$component->foo();
如您所見,雖然 $component
未定義 prop1
和 foo()
,但由於附加的行為,它們可以像元件定義的一部分一樣使用。
如果兩個行為定義了相同的屬性或方法,並且它們都附加到同一個元件,則首先附加到元件的行為在存取屬性或方法時將優先。
行為可以在附加到元件時與名稱關聯。 如果是這種情況,您可以使用名稱存取行為物件
$behavior = $component->getBehavior('myBehavior');
您也可以取得附加到元件的所有行為
$behaviors = $component->getBehaviors();
要分離行為,請使用與行為關聯的名稱呼叫 yii\base\Component::detachBehavior()
$component->detachBehavior('myBehavior1');
您也可以分離所有行為
$component->detachBehaviors();
TimestampBehavior
¶總結一下,讓我們看看 yii\behaviors\TimestampBehavior。 此行為支援在每次透過 insert()
、update()
或 save()
方法儲存模型時自動更新 Active Record 模型的時間戳記屬性。
首先,將此行為附加到您計劃使用的 Active Record 類別
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::class,
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
// if you're using datetime instead of UNIX timestamp:
// 'value' => new Expression('NOW()'),
],
];
}
}
上面的行為配置指定當記錄正在
created_at
和 updated_at
屬性updated_at
屬性注意: 為了使上述實作能夠與 MySQL 資料庫協同運作,請將欄位 (
created_at
、updated_at
) 宣告為 int(11) 以作為 UNIX 時間戳記。
有了該程式碼,如果您有一個 User
物件並嘗試儲存它,您會發現它的 created_at
和 updated_at
會自動填入目前的 UNIX 時間戳記
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // shows the current timestamp
TimestampBehavior 也提供了一個有用的方法 touch(),它會將目前的時間戳記指派給指定的屬性並將其儲存到資料庫
$user->touch('login_time');
有幾個內建和外部行為可用
雖然行為與 traits 相似,因為它們都將其屬性和方法「注入」到主要類別中,但它們在許多方面有所不同。 如下所述,它們各有優缺點。 它們更像是彼此的補充,而不是替代品。
行為類別與一般類別一樣,支援繼承。 另一方面,Traits 可以被視為語言支援的複製和貼上。 它們不支援繼承。
行為可以動態地附加和分離到元件,而無需修改元件類別。 若要使用 trait,您必須修改使用它的類別的程式碼。
行為是可配置的,而 traits 則不是。
行為可以透過回應元件的事件來自訂元件的程式碼執行。
當附加到同一個元件的不同行為之間可能存在名稱衝突時,衝突會透過優先處理首先附加到元件的行為來自動解決。 由不同 traits 引起的名稱衝突需要手動解決,方法是重新命名受影響的屬性或方法。
Traits 比行為有效率得多,因為行為是物件,需要時間和記憶體。
IDE 對 traits 更友善,因為它們是原生語言結構。
發現錯字或您認為此頁面需要改進嗎?
在 github 上編輯 !
若要執行預設動作,請宣告 init() 函式如下
註冊 或 登入 以發表評論。